package com.softkey;

public class encrypt {

    //使用增强算法，加密字符串
    public static String StrEnc(String InString, String Key) {

        byte[] b, outb;
        byte[] temp_b = InString.getBytes();
        byte[] temp = new byte[8], outtemp = new byte[8];
        int n, i, nlen, outlen;
        String outString;

        nlen = temp_b.length;
        nlen = nlen + 1;
        if (nlen < 8)
            outlen = 8;
        else
            outlen = nlen;
        b = new byte[outlen];
        outb = new byte[outlen];

        for (n = 0; n < nlen - 1; n++) {
            b[n] = temp_b[n];
        }

        outb = b.clone();

        for (n = 0; n <= outlen - 8; n = n + 8) {
            for (i = 0; i < 8; i++) temp[i] = b[i + n];
            EnCode(temp, outtemp, Key);
            for (i = 0; i < 8; i++) outb[i + n] = outtemp[i];
        }

        outString = "";
        for (n = 0; n <= outlen - 1; n++) {
            outString = outString + myhex(outb[n]);
        }
        return outString;
    }

    //使用增强算法，解密字符串
    public static String StrDec(String InString, String Key) {

        byte[] b, outb;
        byte[] temp = new byte[8], outtemp = new byte[8];
        int n, i, nlen, outlen;
        String outString, temp_String;


        nlen = InString.length();
        if (nlen < 16) outlen = 16;
        outlen = nlen / 2;
        b = new byte[outlen];
        outb = new byte[outlen];

        i = 0;
        for (n = 1; n <= nlen; n = n + 2) {
            temp_String = InString.substring(n - 1, n - 1 + 2);
            b[i] = (byte) HexToInt(temp_String);
            i = i + 1;
        }

        outb = b.clone();

        for (n = 0; n <= outlen - 8; n = n + 8) {
            for (i = 0; i < 8; i++) temp[i] = b[i + n];
            DeCode(temp, outtemp, Key);
            for (i = 0; i < 8; i++) outb[i + n] = outtemp[i];
        }

        outString = new String(outb);
        outString = outString.trim();
        return outString;
    }

    private static void DeCode(byte[] inb, byte[] outb, String Key) {
        long cnDelta, y, z, a, b, c, d, temp_2;
        long[] buf = new long[16];
        int n, i, nlen;
        long sum;
        long temp, temp_1;
        long mask = 4294967295L;
        //UInt32 temp, temp_1;
        String temp_String;
        cnDelta = 2654435769L;
        sum = 3337565984L;
        nlen = Key.length();
        i = 0;
        for (n = 1; n <= nlen; n = n + 2) {
            temp_String = Key.substring(n - 1, n - 1 + 2);
            buf[i] = HexToInt(temp_String);
            i = i + 1;
        }
        a = 0;
        b = 0;
        c = 0;
        d = 0;
        for (n = 0; n <= 3; n++) {
            a = (buf[n] << (n * 8)) | a;
            b = (buf[n + 4] << (n * 8)) | b;
            c = (buf[n + 4 + 4] << (n * 8)) | c;
            d = (buf[n + 4 + 4 + 4] << (n * 8)) | d;
        }
        y = 0;
        z = 0;
        for (n = 0; n <= 3; n++) {
            temp_2 = conver(inb[n]);
            y = (temp_2 << (n * 8)) | y;
            temp_2 = conver(inb[n + 4]);
            z = (temp_2 << (n * 8)) | z;
        }
        n = 32;
        while (n > 0) {
            temp = (y << 4) & mask;
            temp = (temp + c) & mask;
            temp_1 = (y + sum) & mask;
            temp = (temp ^ temp_1) & mask;
            temp_1 = (y >> 5) & mask;
            temp_1 = (temp_1 + d) & mask;
            temp = (temp ^ temp_1) & mask;
            temp = (z - temp) & mask;
            z = temp & mask;
            /* z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); */

            temp = (z << 4) & mask;
            temp = (temp + a) & mask;
            temp_1 = (z + sum) & mask;
            temp = (temp ^ temp_1) & mask;
            temp_1 = (z >> 5) & mask;
            temp_1 = (temp_1 + b) & mask;
            temp = (temp ^ temp_1) & mask;
            temp = (y - temp) & mask;
            y = temp & mask;
            /*y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); */

            sum = (sum - cnDelta) & mask;
            n = n - 1;

        }
        for (n = 0; n <= 3; n++) {
            outb[n] = (byte) ((y >>> (n * 8)) & 255);
            outb[n + 4] = (byte) ((z >>> (n * 8)) & 255);
        }
    }

    private static void EnCode(byte[] inb, byte[] outb, String Key) {

        long cnDelta, y, z, a, b, c, d, temp_2;
        long[] buf = new long[16];
        int n, i, nlen;
        long sum;
        long temp, temp_1;
        long mask = 4294967295L;

        //UInt32 temp, temp_1;
        String temp_String;


        cnDelta = 2654435769L;
        sum = 0;

        nlen = Key.length();
        i = 0;
        for (n = 1; n <= nlen; n = n + 2) {
            temp_String = Key.substring(n - 1, n - 1 + 2);
            buf[i] = HexToInt(temp_String);
            i = i + 1;
        }
        a = 0;
        b = 0;
        c = 0;
        d = 0;
        for (n = 0; n <= 3; n++) {
            a = (buf[n] << (n * 8)) | a;
            b = (buf[n + 4] << (n * 8)) | b;
            c = (buf[n + 4 + 4] << (n * 8)) | c;
            d = (buf[n + 4 + 4 + 4] << (n * 8)) | d;
        }


        y = 0;
        z = 0;
        for (n = 0; n <= 3; n++) {
            temp_2 = conver(inb[n]);
            y = (temp_2 << (n * 8)) | y;
            temp_2 = conver(inb[n + 4]);
            z = (temp_2 << (n * 8)) | z;
        }


        n = 32;

        while (n > 0) {
            sum = (cnDelta + sum) & mask;

            temp = (z << 4) & mask;
            temp = (temp + a) & mask;
            temp_1 = (z + sum) & mask;
            temp = (temp ^ temp_1) & mask;
            temp_1 = (z >> 5) & mask;
            temp_1 = (temp_1 + b) & mask;
            temp = (temp ^ temp_1) & mask;
            temp = (temp + y) & mask;
            y = temp & mask;
            /*y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); */

            temp = (y << 4) & mask;
            temp = (temp + c) & mask;
            temp_1 = (y + sum) & mask;
            temp = (temp ^ temp_1) & mask;
            temp_1 = (y >> 5) & mask;
            temp_1 = (temp_1 + d) & mask;
            temp = (temp ^ temp_1) & mask;
            temp = (z + temp) & mask;
            z = temp & mask;
            /* z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); */
            n = n - 1;

        }
        for (n = 0; n <= 3; n++) {
            outb[n] = (byte) ((y >>> (n * 8)) & 255);
            outb[n + 4] = (byte) ((z >>> (n * 8)) & 255);
        }
    }

    private static String myhex(byte indata) {
        String outString;
        outString = String.format("%X", indata);
        if (outString.length() < 2) outString = "0" + outString;
        return outString;
    }

    //若某字节为负数则需将其转成无符号正数
    private static long conver(byte temp) {
        long tempInt = (int) temp;
        if (tempInt < 0) {
            tempInt += 256;
        }
        return tempInt;
    }

    //以下用于将16进制字符串转化为无符号长整型
    private static int HexToInt(String s) {
        String[] hexch = {"0", "1", "2", "3", "4", "5", "6", "7",
                "8", "9", "A", "B", "C", "D", "E", "F"};
        int i, j;
        int r, n, k;
        String ch;

        k = 1;
        r = 0;
        for (i = s.length(); i > 0; i--) {
            ch = s.substring(i - 1, i - 1 + 1);
            n = 0;
            for (j = 0; j < 16; j++) {
                if (ch.compareToIgnoreCase(hexch[j]) == 0) {
                    n = j;
                }
            }
            r += (n * k);
            k *= 16;
        }
        return r;
    }
}
